package com.aiwhose.aiwhosefile.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.aiwhose.aiwhosecore.bean.Result;
import com.aiwhose.aiwhosefile.bean.FileQiniuSecurity;
import com.aiwhose.aiwhosefile.bean.QiniuyunPojo;
import com.qiniu.cdn.CdnManager;
import com.qiniu.cdn.CdnResult;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * @author zhubayi
 * 七牛云工具类
 */
@Slf4j
public class QiniuYunUtils {

    /**
     * 获取上传token
     *
     * @param fileQiniuSecurity
     * @return
     */
    public static String getQiniuAuthorization(FileQiniuSecurity fileQiniuSecurity, String url, String method, byte[] body ) {

        //默认不指定key的情况下，以文件内容的hash值作为文件名
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        return auth.signQiniuAuthorization(url, method, body, "application/json");


    }

    /**
     * 获取上传token
     *
     * @param
     * @return
     */
    public static String getToken(FileQiniuSecurity fileQiniuSecurity, String path) {

        //默认不指定key的情况下，以文件内容的hash值作为文件名
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());

        StringMap putPolicy = new StringMap();
        putPolicy.put("scope", fileQiniuSecurity.getBucketName());
//        putPolicy.put("callbackUrl", "http://plublic.aiwhose.com");
        putPolicy.put("callbackBody", "key=$(key)&hash=$(etag)&bucket=$(bucket)&fsize=$(fsize)");
        putPolicy.put("callbackBodyType", "application/json");
        long expireSeconds = 3600;
        String upToken = auth.uploadToken(fileQiniuSecurity.getBucketName(), path, expireSeconds, putPolicy);

        return upToken;
    }

    //上传文件
    public static String uploadQiniu(byte[] bytes, String filePath, FileQiniuSecurity fileQiniuSecurity ) throws QiniuException {
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration();
        if ("z0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huadong());
        }else if ("z1".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huabei());
        }else if ("z2".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huanan());
        }else if ("na0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.regionNa0());
        }else if ("as0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.regionAs0());
        }

        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //默认不指定key的情况下，以文件内容的hash值作为文件名
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        String upToken = auth.uploadToken(fileQiniuSecurity.getBucketName());
        try {
            Response response = uploadManager.put(bytes, filePath, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = BeanUtil.toBean(JSONUtil.parse(response.bodyString()), DefaultPutRet.class);
            return putRet.key;
        } catch (QiniuException ex) {
            Response r = ex.response;
            System.err.println(r.toString());
            try {
                System.err.println(r.bodyString());
                return null;
            } catch (QiniuException ex2) {
                //ignore
                return null;
            }
        }
    }

    //上传文件
    public static String reUploadQiniu(byte[] bytes, String user, String fileName, FileQiniuSecurity fileQiniuSecurity) throws QiniuException {
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration();
        if ("z0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huadong());
        }else if ("z1".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huabei());
        }else if ("z2".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huanan());
        }else if ("na0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.regionNa0());
        }else if ("as0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.regionAs0());
        }
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //默认不指定key的情况下，以文件内容的hash值作为文件名
        String key;

        for (int i = 0; i < 3; i++) {
            fileName = fileName.substring(fileName.indexOf("/") + 1);
        }
        deleteFileFromQiniu(fileName, fileQiniuSecurity);
        key = fileName;

        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        String upToken = auth.uploadToken(fileQiniuSecurity.getBucketName());
        try {
            Response response = uploadManager.put(bytes, key, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = BeanUtil.toBean(JSONUtil.parse(response.bodyString()), DefaultPutRet.class);
            return putRet.key;
        } catch (QiniuException ex) {
            Response r = ex.response;
            System.err.println(r.toString());
            try {
                System.err.println(r.bodyString());
                return null;
            } catch (QiniuException ex2) {
                //ignore
                return null;
            }
        }
    }

    //删除文件

    /**
     * @param fileName     文件名
     * @param fileQiniuSecurity
     * @return
     */
    public static Response deleteFileFromQiniu(String fileName,  FileQiniuSecurity fileQiniuSecurity) {
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration();
        if ("z0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huadong());
        }else if ("z1".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huabei());
        }else if ("z2".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.huanan());
        }else if ("na0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.regionNa0());
        }else if ("as0".equals(fileQiniuSecurity.getBucketRegion())){
            cfg= new Configuration(Region.regionAs0());
        }
        String key = fileName;
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        BucketManager bucketManager = new BucketManager(auth, cfg);
        try {
            return bucketManager.delete(fileQiniuSecurity.getBucketName(), key);
        } catch (QiniuException ex) {
            //如果遇到异常，说明删除失败
            System.err.println(ex.code());
            System.err.println(ex.response.toString());
        }
        return null;
    }
    //批量删除文件

    /**
     * @param keyList      文件名
     * @param fileQiniuSecurity
     * @return
     */
    public static Result deleteFilesFromQiniu(String[] keyList,  FileQiniuSecurity fileQiniuSecurity) {
        //构造一个带指定 Region 对象的配置类
        Configuration cfg = new Configuration(Region.region0());
//...其他参数参考类注释
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        BucketManager bucketManager = new BucketManager(auth, cfg);
        ArrayList<String> errorFiles = new ArrayList<>();
        try {
            //单次批量请求的文件数量不得超过1000
            BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
            batchOperations.addDeleteOp(fileQiniuSecurity.getBucketName(), keyList);
            Response response = bucketManager.batch(batchOperations);
            BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);

            for (int i = 0; i < keyList.length; i++) {
                BatchStatus status = batchStatusList[i];
                String key = keyList[i];
                System.out.print(key + "\t");
                if (status.code == 200) {
                    log.info(keyList[i] + "删除成功！");
                } else {
                    log.error(keyList[i] + "删除失败！");
                    log.error(status.data.error);
                    errorFiles.add(keyList[i]);
                }
            }
        } catch (QiniuException ex) {
            log.error(ex.response.toString());
            return Result.error("删除异常！");
        }
        if (errorFiles.size() > 0) {
            return Result.error(errorFiles.size() + "个失败", errorFiles);
        } else {
            return Result.ok();
        }

    }

    /**
     * 获取文件列表
     *
     * @param maxLimit     每次迭代的长度限制，最大1000，推荐值 1000   maxLimit=1000
     * @param prefix       文件名前缀 prefix      = "kmu/2022/";
     * @param delimiter    指定目录分隔符，列出所有公共前缀（模拟列出目录效果）。缺省值为空字符串 delimiter   String delimiter = "";
     * @param fileQiniuSecurity
     * @return
     */
    public static BucketManager.FileListIterator getFileList(Integer maxLimit, String prefix, String delimiter,  FileQiniuSecurity fileQiniuSecurity) {

        //构造一个带指定 Region 对象的配置类
        Configuration cfg = new Configuration(Region.region0());
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        BucketManager bucketManager = new BucketManager(auth, cfg);
        BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(fileQiniuSecurity.getBucketName(), prefix, maxLimit, delimiter);

        return fileListIterator;
    }


    /**
     * 获取 域名流量
     *
     * @param fromDate     开始日期  "2017-01-02";
     * @param toDate       结束日期     "2017-02-02";
     * @param granularity  数据粒度，支持的取值为 granularity 5min ／ hour ／day    "day";
     * @param qiniuyunPojo
     * @return
     */
    public HashMap<String, Object> getCDNTraffic(String fromDate, String toDate, String granularity, QiniuyunPojo qiniuyunPojo) {
        Auth auth = Auth.create(qiniuyunPojo.getAccessKey(), qiniuyunPojo.getSecretKey());
        CdnManager c = new CdnManager(auth);
//域名列表
        String[] domains = new String[]{
                qiniuyunPojo.getDomainOfBucket()
        };
        try {
            CdnResult.FluxResult fluxResult = c.getFluxData(domains, fromDate, toDate, granularity);

            HashMap<String, Object> map = new HashMap<>();
            if (fluxResult.code == 200) {
                String[] time = fluxResult.time;
                Long[] china = fluxResult.data.get(qiniuyunPojo.getDomainOfBucket()).china;

                for (int i = 0; i < time.length; i++) {
                    Date date = DateUtil.parse(time[i]);
                    time[i] = DateUtil.format(date, "MM月dd日");
                    china[i] = china[i] / 1000 / 1000;
                }
                map.put("time", time);
                map.put("china", china);

            }
            return map;
            //处理得到的结果数据
            //...
        } catch (QiniuException e) {
            System.err.println(e.response.toString());
        }
        return null;

    }


    /**
     * 获取 域名带宽
     *
     * @param fromDate     开始日期  "2017-01-02";
     * @param toDate       结束日期     "2017-02-02";
     * @param granularity  数据粒度，支持的取值为 granularity 5min ／ hour ／day    "day";
     * @param qiniuyunPojo
     * @return
     */
    public HashMap<String, Object> getCNDWidth(String fromDate, String toDate, String granularity, QiniuyunPojo qiniuyunPojo) {
        Auth auth = Auth.create(qiniuyunPojo.getAccessKey(), qiniuyunPojo.getSecretKey());
        CdnManager c = new CdnManager(auth);
//域名列表
        String[] domains = new String[]{
                qiniuyunPojo.getDomainOfBucket()
        };

        try {
            CdnResult.BandwidthResult bandwidthResult = c.getBandwidthData(domains, fromDate, toDate, granularity);
            //处理得到的结果数据
            HashMap<String, Object> map = new HashMap<>();
            if (bandwidthResult.code == 200) {
                String[] time = bandwidthResult.time;
                Long[] china = bandwidthResult.data.get(qiniuyunPojo.getDomainOfBucket()).china;

                for (int i = 0; i < time.length; i++) {
                    Date date = DateUtil.parse(time[i]);
                    time[i] = DateUtil.format(date, "MM月dd日");
                    china[i] = china[i] / 1000;
                }

                map.put("time", time);
                map.put("china", china);

            }
            return map;
        } catch (QiniuException e) {
            System.err.println(e.response.toString());
        }
        return null;

    }


    /**
     * 刷新文件
     *
     * @param urls         刷新路径 "https://tgg.cloudtgg.com/cloud/202308150940127.zip"
     * @param fileQiniuSecurity
     */
    public static void refreshCache(String[] urls,FileQiniuSecurity fileQiniuSecurity) {
        //待刷新的链接列表  urls
        System.out.println(urls[0]);
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        CdnManager c = new CdnManager(auth);
        try {
            //单次方法调用刷新的链接不可以超过100个
            CdnResult.RefreshResult result = c.refreshUrls(urls);
            System.out.println(result.code);
            //获取其他的回复内容
        } catch (QiniuException e) {
            System.err.println(e.response.toString());
        }
    }


    /**
     * 文件下载
     * @param fileName
     * @param time
     * @param fileQiniuSecurity
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String download(String fileName, Long time, FileQiniuSecurity fileQiniuSecurity) throws UnsupportedEncodingException {
        String encodedFileName = URLEncoder.encode(fileName, "utf-8").replace("+", "%20");
        String publicUrl = String.format("%s/%s", fileQiniuSecurity.getBucketUrl(), encodedFileName);
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        long expireInSeconds = time;// 可以自定义链接过期时间,单位秒
        String finalUrl = auth.privateDownloadUrl(publicUrl, expireInSeconds);
        return finalUrl;
    }
    /**
     * 获取文件地址

     * @param fileQiniuSecurity
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String getPrivateUrl(String  url, FileQiniuSecurity fileQiniuSecurity) throws UnsupportedEncodingException {
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        long expireInSeconds = 60*60L;// 可以自定义链接过期时间,单位秒
        return auth.privateDownloadUrl(url, expireInSeconds);
    }

    // 移动或者重命名文件
    public static boolean moveOrRenameFiles(String originalBucket, String originalfilePath, String laterBucket, String laterKey, FileQiniuSecurity fileQiniuSecurity) throws UnsupportedEncodingException, QiniuException {
        Auth auth = Auth.create(fileQiniuSecurity.getAccessKey(), fileQiniuSecurity.getSecretKey());
        //构造一个带指定 Region 对象的配置类
        Configuration cfg = new Configuration(Region.region0());
        BucketManager bucketManager = new BucketManager(auth, cfg);
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();

        batchOperations.addMoveOp(originalBucket, originalfilePath, laterBucket, laterKey);
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
        if (batchStatusList[0].code == 200) {
            System.out.println("move success");
            return true;
        } else {
            System.out.println(batchStatusList[0].data.error);
            return false;
        }
    }



    //    生成文件上传路径
    public static String createPath(String fileName) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();

        // 定义时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd/HH/mm");

        // 将当前时间格式化为字符串
        String formattedDateTime = now.format(formatter);

        String id2 = IdUtil.objectId();
//        s = s.substring(2);
        String fileType = fileName.substring(fileName.lastIndexOf('.') + 1);

        return "/" + formattedDateTime + id2 + "." + fileType;
    }

    public static void main(String[] args) {

    }

}